package com.woniu.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniu.JwtTemplate;
import com.woniu.Result;
import com.woniu.enums.ResultCode;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.concurrent.TimeUnit;

// 鉴权
@Component
@Slf4j
public class AuthFilter implements GlobalFilter {

    @Autowired(required = false)
    private JwtTemplate jwtTemplate;

    @Autowired(required = false)
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1、获取请求的url
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        // 服务器返回对象
        ServerHttpResponse response = exchange.getResponse();

        AntPathMatcher pathMatcher = new AntPathMatcher();
        // 2、拦截请求url
        boolean userMatch = pathMatcher.match("/**/user-auth/**", path);
        System.out.println("userMatch = " + userMatch);
        // 2、拦截请求url
        boolean shopMatch = pathMatcher.match("/**/shop-auth/**", path);
        System.out.println("shopMatch = " + shopMatch);
        // 2、拦截请求url
        boolean adminMatch = pathMatcher.match("/**/admin-auth/**", path);
        System.out.println("adminMatch = " + adminMatch);
        if(userMatch){
            //进行业务逻辑处理
            // 3、拿到头信息
            String authorization = exchange.getRequest().getHeaders().getFirst("Authorization");

            if (StringUtils.isEmpty(authorization)){
                return  error(response);
            }
            // 4、拿到token
            String token = authorization.replace("Bearer ", "");
            System.out.println("token = " + token);

            // 5、校验token
            boolean verifyToken = jwtTemplate.verifyToken(token);
            if(!verifyToken){
                // token 校验失败
                log.info("校验失败");
                return error(response);
            }

            // 6、解析token
            Integer userId = (Integer) jwtTemplate.parseToken(token,"userId");
            // 7、判断token是否过期没有
            String key = "CAR:USER_ID" + userId;
            String redisToken = stringRedisTemplate.opsForValue().get(key);
            if(StringUtils.isEmpty(redisToken)){
                log.info("token过期了.......");
                return error(response);
            }

            // 8、修改头信息
            ServerHttpRequest.Builder mutate = request.mutate();
            mutate.header("userId", userId + "");

            // 9、续签
            stringRedisTemplate.expire(key, 30, TimeUnit.MINUTES);
        }else if(shopMatch){
            //进行业务逻辑处理
            // 3、拿到头信息
            String authorization = exchange.getRequest().getHeaders().getFirst("Authorization");

            if (StringUtils.isEmpty(authorization)){
                return  error(response);
            }
            // 4、拿到token
            String token = authorization.replace("Bearer ", "");
            System.out.println("token = " + token);

            // 5、校验token
            boolean verifyToken = jwtTemplate.verifyToken(token);
            if(!verifyToken){
                // token 校验失败
                log.info("校验失败");
                return error(response);
            }

            // 6、解析token
            Integer shopId = (Integer) jwtTemplate.parseToken(token,"shopId");
            // 7、判断token是否过期没有
            String key = "CAR:SHOP_ID" + shopId;
            String redisToken = stringRedisTemplate.opsForValue().get(key);
            if(StringUtils.isEmpty(redisToken)){
                log.info("token过期了.......");
                return error(response);
            }

            // 8、修改头信息
            ServerHttpRequest.Builder mutate = request.mutate();
            mutate.header("shopId", shopId + "");

            // 9、续签
            stringRedisTemplate.expire(key, 30, TimeUnit.MINUTES);
        }else if(adminMatch){
            //进行业务逻辑处理
            // 3、拿到头信息
            String authorization = exchange.getRequest().getHeaders().getFirst("Authorization");

            if (StringUtils.isEmpty(authorization)){
                return  error(response);
            }
            // 4、拿到token
            String token = authorization.replace("Bearer ", "");
            System.out.println("token = " + token);

            // 5、校验token
            boolean verifyToken = jwtTemplate.verifyToken(token);
            if(!verifyToken){
                // token 校验失败
                log.info("校验失败");
                return error(response);
            }

            // 6、解析token
            Integer adminId = (Integer) jwtTemplate.parseToken(token,"adminId");
            // 7、判断token是否过期没有
            String key = "CAR:ADMIN_ID" + adminId;
            String redisToken = stringRedisTemplate.opsForValue().get(key);
            if(StringUtils.isEmpty(redisToken)){
                log.info("token过期了.......");
                return error(response);
            }

            // 8、修改头信息
            ServerHttpRequest.Builder mutate = request.mutate();
            mutate.header("adminId", adminId + "");

            // 9、续签
            stringRedisTemplate.expire(key, 30, TimeUnit.MINUTES);
        }
        return chain.filter(exchange);
    }


    // 自动处理检查异常的注解
    @SneakyThrows
    private Mono<Void> error(ServerHttpResponse response)  {
        // 创建一个 返回结果
        Result<String> result = Result.fail(ResultCode.PERMISSION_NO_ACCESS);

        ObjectMapper objectMapper = new ObjectMapper();
        byte[] bytes = objectMapper.writeValueAsBytes(result);

        //把 bytes写到内存中
        DataBuffer dataBuffer = response.bufferFactory().wrap(bytes);

        return response.writeWith(Mono.just(dataBuffer));
    }
}
